var draggableDefaults = {
    nameSpace: 'draggable', //命名空间，一个对象可以绑定多种拖动实现
    which: undefined, //鼠标键码，是否左键,右键 才能触发拖动，默认左右键均可 1,3
    defaultZindex: 999999, //当z-index为auto时采用的层级数值
    holdTime: undefined, //按下鼠标多少毫秒才拖动，默认不设置立即可拖动
    globalDraging:true,//是否是全局拖动，避免多层触发拖动
    isProxy: false, //是否产生一个空代理进行拖动
    disabled: false, //是否禁用拖动
    handler: undefined, //触发拖动的对象，默认是对象本身
    cursor: 'move', //鼠标样式
    axis: undefined, // v垂直方 h水平，默认全向   
    setMatrixRate:undefined,//设置缩放比例        
    onDragReady: undefined, //鼠标按下时候准备拖动前，返回true则往下执行，返回false则停止
    onStartDrag: undefined, //开始拖动事件
    onDrag: undefined, //拖动中事件
    onStopDrag: undefined, //拖动结束事件
    onMouseUp: undefined, //当没有发生拖动，鼠标放开时候调用
    onProxyEnd: undefined, // function(args,pos) 代理拖动结束，返回false则不更新代理
    onCreateProxy: undefined // function(proxyObj,srcObj)，代理创建监听
};
/***1.5秒后及时清理state上的引用****/
function clearDragArgs(state) {
    setTimeout(function () {
        for (var p in state) {
            if (state.hasOwnProperty(p)) {
                delete state[p];
            }
        }
    }, 1500);
}
/***
 * 根据鼠标计算位置
 * ****/
function _compute(e) {
    var state = e.params,
        data = state._data,
        opts = state.options;
    //拖动后的 = 原先+拖动位移
    var leftOffset = e.pageX - data.startX,
        topOffset = e.pageY - data.startY;
    if (opts.axis === 'v') { //如果是垂直，则只改top
        leftOffset = 0;
    } else if (opts.axis === 'h') { //如果是水平拖动 则只改left
        topOffset = 0;
    }
    var left = data.startLeft + leftOffset,
        top = data.startTop + topOffset;
    data.leftOffset = leftOffset;
    data.topOffset = topOffset;
    data.oldLeft = data.left;
    data.oldTop = data.top;
    data.left = left;
    data.top = top;
    var apply = true;
    if (state["onDragFn"]) {
        var args = {
            shiftKey:e.shiftKey,
            ctrlKey:e.ctrlKey,
            altKey:e.altKey,
            state: state,
            which: opts.which
        };
        var res = opts.onDrag(args);
        if (typeof res !== 'undefined') {
            apply = res;
        }
    }    
    data["apply"] = apply;
}
//移动事件 hasCallStartFn
function _docMove(e) {
    var state = e.params;
    var opts = state.options;
    var data = state._data;
    data.pageX = e.pageX;
    data.pageY = e.pageY;
    /***** 是否已经调研了 onStartDrag *********/
    if (!state["hasCallStartFn"]) {
        //处理没有发生鼠标移动但是_docMove被触发的情况！！
        var leftOffset = e.pageX - data.startX,
            topOffset = e.pageY - data.startY;
        if (leftOffset === 0 && topOffset === 0) {
            console.log("过滤没有发生实际移动的 _docMove");
            return;
        }
        state["hasCallStartFn"] = true;       
        if (state.callStartDragFn) {
            //提取拖动目标的zIndex 2147483647
            //var zIndex = state.movingTarget.css("z-index");
            var zIndex = $B.DomUtils.css(state.movingTarget,"zIndex");
            if (zIndex === "auto") {
                zIndex = opts.defaultZindex;
            }
            state["zIndex"] = zIndex;
            //state.movingTarget.css("z-index", 2147483647);
            $B.DomUtils.css(state.movingTarget,{"z-index":2147483647});
            try {                
                opts.onStartDrag({
                    shiftKey:e.shiftKey,
                    ctrlKey:e.ctrlKey,
                    altKey:e.altKey,
                    state: state
                });
            } catch (ex) {
                if (console.error) {
                    console.error("onStartDrag error " + ex);
                } else {
                    console.log("onStartDrag error " + ex);
                }
            }
        }
    }
    _compute(e);
    if (data["apply"] && state.movingTarget) {
        if (data.matrixRate) { //存在缩放比例
            data.top = data.top / data.matrixRate;
            data.left = data.left / data.matrixRate;
        }
        var css = {
            cursor: state.options.cursor
        };
        if (opts.axis === 'v') {
            css.top = data.top + data.fixTop;
        } else if (opts.axis === 'h') {
            css.left = data.left + data.fixLeft;
        } else {
            css.top = data.top + data.fixTop;
            css.left = data.left + data.fixLeft;
        }
        //确保为整数
        css.top = parseInt(css.top);
        css.left = parseInt(css.left);
        $B.DomUtils.css(state.movingTarget,css);
    }
    if (typeof opts.notClearRange === "undefined") {
        //先清除document中的选择区域
        $B.clearDomSelected();
    }
}
/***
 * 应该domcument监听鼠标放开事件
 * ***/
function _docUp(e) {
    var state = e.params,
        data = state._data,
        opts = state.options,
        nameSpace = opts.nameSpace,
        target = state.target,
        body = $B.getBody();
    data.pageX = e.pageX;
    data.pageY = e.pageY;
    $B.DomUtils.offEvents(window.document,nameSpace+".*");
    $B.DomUtils.css(target,{"cursor":data.srcsor});
    window["_globalDraging"] = undefined;
    if (opts.isProxy) { //代理移动方式,则需要更新目标位置           
        var css = {
            left: data.srcPos.left + data.leftOffset,
            top: data.srcPos.top + data.topOffset
        };
        var go = true;
        if (opts.onProxyEnd) {
            var ret = opts.onProxyEnd(state, css);
            if (typeof ret !== "undefined") {
                go = ret;
            }
        }
        $B.DomUtils.remove(state["movingTarget"]);
        if (go) {
            css["position"] = "absolute";
            $B.DomUtils.css(target,css);
        }
    }
    var onStopDrag = opts.onStopDrag;
    var returnVar;
    if (typeof onStopDrag === "function" && state["hasCallStartFn"]) {
        returnVar = onStopDrag({
            shiftKey:e.shiftKey,
            ctrlKey:e.ctrlKey,
            altKey:e.altKey,
            state: state,
            e:e._e
        });
    }    
    if (state["hasCallStartFn"]) {
        var zIndex = state["zIndex"];
        $B.DomUtils.css(state.movingTarget,{"z-index":zIndex});
    } else {
        if (opts.onMouseUp) {
           let v = opts.onMouseUp({
                state: state,
                e:e._e
            });
            if(typeof v !== "undefined"){
                returnVar = v;
            }
        }
    }
    clearDragArgs();
    $B.DomUtils.css(body,{"cursor":"default"});
    if (typeof returnVar !== "undefined") {
        return returnVar;
    }
}
//监听document鼠标按下事件
function _docDown(e) {
    var state = e.params,
        opts = state.options,
        data = state._data;
    var movingTarget = state.target;
    var body = $B.getBody();
    if (opts.isProxy) {
        var ofs = data.srcOfs,
            w = data.width,
            h = data.height,
            fs = $B.DomUtils.css(state.target,"font-size"),
            fcolor = $B.DomUtils.css(state.target,"color");
        var pp = $B.DomUtils.css(state.target,"padding") ;
        var clz = "";
        if ($B.DomUtils.hasClass(state.target,"k_box_size")) {
            clz = "k_box_size";
        }
        movingTarget = $B.DomUtils.createEl("<div style='background-color:#ADADAD;opacity :0.6;font-size:" + fs + ";color:" + fcolor + ";padding:" + pp + ";cursor:" + opts.cursor + ";position:absolute;top:" + ofs.top + "px;left:" + ofs.left + "px' class='k_draggable_proxy " + clz + "'></div>");
         $B.DomUtils.width(movingTarget,w);
        $B.DomUtils.height(movingTarget,h);
        if (opts.onCreateProxy) {
            opts.onCreateProxy(movingTarget, state.target, e);
        }
        $B.DomUtils.append(body,movingTarget);
    }
    if (typeof opts.onDrag === "function") {
        state["onDragFn"] = true;
    }
    state["movingTarget"] = movingTarget;    
    $B.DomUtils.css(body,{"cursor":opts.cursor});
}
/***
 * 鼠标放开
 ****/
function onMouseUp(e) {
    window["_globalDraging"] = undefined;
    var dragtimer = $B.DomUtils.propData(this,"dragtimer");
    if (dragtimer) {
        clearTimeout(dragtimer);
        var state = e.params;
        $B.DomUtils.removePropData(this,"dragtimer");
        if (!state["hasCallStartFn"]) { //如果没有发生拖动
            var opts = state.options;
            if (opts.onMouseUp) {
                opts.onMouseUp({
                    state: state,
                    e:e._e
                });
            }
        }
        clearDragArgs(state);
    }
}
/**
 * args应对编程trigger触发的鼠标事件
 * e参数中不存在pageX、pageY的情况
 * **/
function onMouseDown(e, args) {   
    if (args && !e["pageX"]) {
        e["pageX"] = args.pageX;
        e["pageY"] = args.pageY;
        e["which"] = args.which;
    }
    if (e.ctrlKey) {       
        return true;
    }
    if(window["_globalDraging"] ){//已经存在全局的拖动
        console.log(" 已经存在全局的拖动");
        return true;
    }
    var state = e.params;
    var el = state.target;
    var options = state.options;
    if (!options.which || options.which === e.which) {
        if (!options.disabled) {
            var go = true;
            if (typeof options.onDragReady === 'function') {
               let ret  = options.onDragReady.call(el, state, e);
               if(typeof ret !== "undefined"){
                go = ret;
               }
            }
            if (go) {
                var posParentEl = el.parentNode;
                var posAttr;
                while (posParentEl ) {
                    posAttr =  $B.DomUtils.css(posParentEl,"position");
                    if (posAttr === "relative" || posAttr === "absolute") {
                        break;
                    }
                    if( posParentEl.nodeName === "BODY"){
                        break;
                    }
                    posParentEl = posParentEl.parentNode;
                }
                var matrix = $B.getMatrixArray(posParentEl); //父元素是否存在缩放
                var matrixRate;
                if (matrix) {
                    matrixRate = matrix[0];
                }
                if (typeof options.setMatrixRate === 'function') {
                    var rate = options.setMatrixRate();
                    if (typeof rate !== "undefined") {
                        matrixRate = rate;
                    }
                }             
                var parentOfs = $B.DomUtils.offset(posParentEl);
                var offset =  $B.DomUtils.offset(el);// $t.offset();
                var position = $B.DomUtils.position(el);
                //如果有css transform旋转，需要计算出 修正的偏移量    
                var ofs = $B.getAnglePositionOffset(el);
                var fixTop = ofs.fixTop;
                var fixLeft = ofs.fixLeft;
                var parent = el.parentNode;            
                var  scrollLeft = $B.DomUtils.scrollLeft(parent);
                var  scrollTop =  $B.DomUtils.scrollTop(parent);
                if(options.setScrollFn){
                    var sclRet = options.setScrollFn(parent);
                    if(typeof sclRet !== "undefined"){
                        scrollLeft = sclRet.scrollLeft;
                        scrollTop = sclRet.scrollTop;
                    }
                }
                var srcsor = el.style.cursor;
                if (!srcsor) {
                    srcsor = 'default';
                }
                var objWidth = $B.DomUtils.outerWidth(el);
                var objHeight = $B.DomUtils.outerHeight(el);
                if (options.isProxy) {
                    /***** 代理是放置于body下的，要用offset替换position *******/
                    position = offset;
                } else {                   
                    var resetCss = {
                        "position": "absolute"
                    };
                    if (options.axis === 'v') {
                        resetCss.top = position.top + fixTop ; //+ scrollTop
                    } else if (options.axis === 'h') {
                        resetCss.left = position.left + fixLeft ;//+ scrollLeft
                    } else {
                        resetCss.top = position.top + fixTop ;//+ scrollTop
                        resetCss.left = position.left + fixLeft ;//+ scrollLeft
                    }
                    if (matrixRate) {
                        resetCss.top = resetCss.top / matrixRate;
                        resetCss.left = resetCss.left / matrixRate;
                        objWidth = objWidth * matrixRate;
                        objHeight = objHeight * matrixRate;
                    }
                    $B.DomUtils.css(el,resetCss);
                    position = $B.DomUtils.position(el);
                }
                //封装拖动数据data对象，记录width,height,pageX,pageY,left 和top 等拖动信息                   
                var data = {
                    matrixRate: matrixRate,
                    parentOfs: parentOfs,
                    srcOfs: offset,
                    srcPos: position,
                    startLeft: position.left , //开始的位置信息	+ scrollLeft
                    startTop: position.top , //开始的位置信息	+ scrollTop
                    scrollLeft: scrollLeft,
                    scrollTop: scrollTop,
                    left: position.left , //当前left位置信息	+ scrollLeft
                    top: position.top , //当前top位置信息       + scrollTop
                    oldLeft: undefined, //旧的left位置 
                    oldTop: undefined, //旧的top位置	
                    startX: e.pageX, //鼠标点击时的x坐标
                    startY: e.pageY, //鼠标点击时的y坐标
                    pageX: e.pageX,
                    pageY: e.pageY,
                    width: objWidth,
                    height: objHeight,
                    fixTop: fixTop,
                    fixLeft: fixLeft,
                    srcsor: srcsor, //原来的鼠标样式
                    leftOffset: 0, //鼠标left偏移
                    topOffset: 0 //鼠标top偏移
                };
                state["hasCallStartFn"] = false; //是否已经调用了onStartDrag   
                state["_data"] = data;
                state["parent"] = parent; //拖动对象的父dom
                state["callStartDragFn"] = typeof options.onStartDrag === "function";
                var nameSpace = options.nameSpace;
                if (typeof options.holdTime !== 'undefined') { //定时触发事件
                    var _this = el;
                    var timer = setTimeout(function () {
                        if(options.onTimeIsUpFn){
                            if(options.onTimeIsUpFn()){
                               return;
                            }
                        }                      
                        if(options.globalDraging){
                            window["_globalDraging"] = true;
                        }                       
                        $B.DomUtils.css(el,{"cursor":state.options.cursor});
                        //往document上绑定鼠标移到监听 
                        _docDown({
                            params:state
                        });
                        $B.DomUtils.removeData(_this,"dragtimer");
                        $B.DomUtils.addListener(window.document,nameSpace+".mousemove",_docMove,state);
                        $B.DomUtils.addListener(window.document,nameSpace+".mouseup",_docUp,state);
                    }, options.holdTime);
                    $B.DomUtils.setData(_this,"dragtimer",timer);
                    $B.DomUtils.addListener(window.document,"clearDragTimer.mouseup",function(e){
                        clearTimeout(e.params.timer);
                        $B.DomUtils.offEvents(window.document,"clearDragTimer.*");
                    },{timer: timer});
                    // $doc.on('mouseup.clearDragTimer', {
                    //     timer: timer
                    // }, function (e) {
                    //     $doc.off('mouseup.clearDragTimer');
                    //     clearTimeout(e.params.timer);
                    // });
                } else {     
                    if(options.globalDraging){
                        window["_globalDraging"] = true;
                    }               
                    $B.DomUtils.css(el,{"cursor":state.options.cursor});
                    if(e.isTrigger){
                        _docDown({
                            params:state
                        });
                    }else{
                        $B.DomUtils.addListener(window.document,nameSpace+".mousedown",_docDown,state);
                    }                   
                    $B.DomUtils.addListener(window.document,nameSpace+".mousemove",_docMove,state);
                    $B.DomUtils.addListener(window.document,nameSpace+".mouseup",_docUp,state);
                }
            }
        }
    }
}
/****
 * 构造函数
 * options：defaults参数
 * *****/
$B.draggable = function (el,options) {
    var nameSpace = "draggable";
    var dragOpt;
    if(typeof el === 'string'){
        el = window.document.getElementById(el);
    }
    if (typeof options === 'string') {
        if (arguments.length > 1) {
            nameSpace = arguments[1];
        }
        var dataKey = nameSpace+"_opt";
        switch (options) {
            case 'enable': //启用拖动
                dragOpt =  $B.getData(el,dataKey).state.options;
                dragOpt.disabled = false;
                el.style.cursor = dragOpt.cursor;
                break;
            case 'disable': //禁用拖动
                dragOpt =  $B.getData(el,dataKey).state.options;
                dragOpt.disabled = false;
                el.style.cursor = "default";
                break;
            case 'unbind': //解除拖动
                let state = $B.getData(el,dataKey).state;
                $B.offEvents(state.handler,nameSpace + '.');
                delete state.handler;
                delete state.target;
                delete state.options;
                delete state.parent;
                $B.removeData(el,dataKey);       
                break;        
            default:
                throw new Error("不支持:" + options);
        }
    }
    var opts = $B.extendObjectFn(true,{},draggableDefaults,options);
    if (opts.nameSpace) {
        nameSpace = opts.nameSpace; //默认的命名空间
    }
    var handler = el; //handler是实际触发拖动的对象
    if (opts.handler) {
        handler = (typeof opts.handler === 'string' ? $B.DomUtils.findbyId(el,opts.handler) : opts.handler);      
        $B.DomUtils.css(handler,{cursor:options.cursor});
    }
    //存在则先解除已经绑定的拖动
    let state = $B.DomUtils.getData(el,nameSpace);
    if (state) {        
        $B.DomUtils.offEvents(state.handler,nameSpace+".*");
        delete state["handler"];
        delete state["target"];
        delete state["parent"];
        delete state["options"];
        delete state["_data"];
    }
    state = {
        handler: handler,
        target: el,
        options: opts
    };
    $B.DomUtils.setData(el,nameSpace, state);
    //注册事件 draggable 为命名空间
    $B.DomUtils.addListener(handler,nameSpace+".mousedown",onMouseDown,state);
    if (typeof opts.holdTime !== 'undefined') {
        $B.DomUtils.addListener(handler,nameSpace+".mouseup",onMouseDown,state);
    }
};